﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace StreetPacMan.FrontEnd
{
    public static class ReflectionAssist
    {
        public static string GetName(Expression<Action> expression)
        {
            return GetImpl(expression).Name;
        }
        public static string GetName<T>(Expression<Action<T>> expression)
        {
            return GetImpl(expression).Name;
        }
        public static string GetName<T>(Expression<Func<T>> expression)
        {
            return GetImpl(expression).Name;
        }
        public static string GetName<TInvoker, TArg1>(Expression<Action<TInvoker, TArg1>> expression)
        {
            return GetImpl(expression).Name;
        }
        public static string GetName<TInvoker, TArg1, TArg2>(Expression<Action<TInvoker, TArg1, TArg2>> expression)
        {
            return GetImpl(expression).Name;
        }

        public static string GetName<TInvoker, TRet>(Expression<Func<TInvoker, TRet>> expression)
        {
            return GetImpl(expression).Name;
        }

        public static MemberInfo Get(Expression<Action> expression)
        {
            return GetImpl(expression);
        }
        public static MemberInfo Get<T>(Expression<Action<T>> expression)
        {
            return GetImpl(expression);
        }
        public static MemberInfo Get<T>(Expression<Func<T>> expression)
        {
            return GetImpl(expression);
        }

        public static MemberInfo Get<T, T1>(Expression<Func<T, T1>> expression)
        {
            return GetImpl(expression);
        }

        private static MemberInfo GetImpl<T>(Expression<T> expression)
        {
            var methodCallExpression = expression.Body as MethodCallExpression;
            if (methodCallExpression != null)
            {
                return methodCallExpression.Method;
            }

            var memberExpression = expression.Body as MemberExpression;
            if (memberExpression != null)
            {
                return memberExpression.Member;
            }
            var constantExpression = expression.Body as ConstantExpression;
            if(constantExpression != null)
            {
                var value = constantExpression.Value;
                if(value==null)
                {
                    throw new ArgumentException("Can't handle consts which are nulls");
                }

                return value.GetType().
                    GetFields(BindingFlags.Static | BindingFlags.Public).
                    Where(x => x.GetRawConstantValue().Equals(value)).Single();
            }

            throw new ApplicationException("Cannot handle expression of type " + expression.GetType());
        }
    }
}